package com.tangding.net.handler;

import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import com.tangding.cache.GamesDataWatchingCache;
import com.tangding.cache.TableWatchingCache;
import com.tangding.common.logx.LogHelp;
import com.tangding.common.utils.AES128;
import com.tangding.common.utils.JacksonUtil;
import com.tangding.config.Config;
import com.tangding.net.pool.BaseNettySessionPool;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.ReferenceCountUtil;

@Scope("prototype")
@Component("gameServerHandler")
public class GameServerHandler extends ChannelInboundHandlerAdapter{
	
	@Autowired
	BaseNettySessionPool pool;
	
	@Override
	public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
		super.handlerAdded(ctx);
	}

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		Channel channel = ctx.channel();
		try{
			byte[] buf = (byte[]) msg;
			MessageReq req = JacksonUtil.readValue(buf, MessageReq.class);
			if ("connect".equals(req.getCmd())) {//绑定请求
				Map<String, Object> data = (Map<String, Object>) req.getData();
				if (!data.containsKey("accessToken") || !data.containsKey("seceret")) {
					ctx.channel().close();//非法请求
					return;
				}
				String uid = req.getUid();
				String accessToken = (String) data.get("accessToken");
				String seceret = (String) data.get("seceret");
				String decrypt = AES128.Decrypt(seceret, Config.AES128_KEY);
				String[] cells = decrypt.split("[|]");
				if (!uid.equals(cells[0]) || !accessToken.equals(cells[1])) {
					ctx.channel().close();//非法请求
					return;
				}

				pool.addSession(ctx.channel(), uid);
			}else if ("heartbeat".equals(req.getCmd())) {//心跳请求
				Map<String, Object> data = (Map<String, Object>) req.getData();
				if (!data.containsKey("accessToken") || !data.containsKey("seceret")) {
					ctx.channel().close();//非法请求
					return;
				}
				String uid = req.getUid();
				String accessToken = (String) data.get("accessToken");
				String seceret = (String) data.get("seceret");
				String decrypt = AES128.Decrypt(seceret, Config.AES128_KEY);
				String[] cells = decrypt.split("[|]");
				if (!uid.equals(cells[0]) || !accessToken.equals(cells[1])) {
					ctx.channel().close();//非法请求
					return;
				}

				Channel c = pool.getChannel(uid);
				if (c == null || !c.isWritable() || !c.isActive()) {
					LogHelp.doLogApp("[" + uid + "]reconnect by heartbeat");
					pool.dropSession(uid);
					pool.addSession(ctx.channel(), uid);
				}
			}else {//不接受的请求，直接关闭连接
				ctx.channel().close();
			}
		}catch(Exception e) {
	    	LogHelp.doLogException(e);
//	    	responseErrorAndClose(ErrorConstants.ERR_ILLEGAL_REQUEST, channel);
	    	channel.close();
	    }finally {
	        ReferenceCountUtil.release(msg);
	    }
	}
	
	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
//		LogHelp.doLogException(cause);
	}
	
	@Override
	public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
		LogHelp.doLogApp("handler removed...");
		releaseResouces(ctx);
	}
	@Override
	public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
		LogHelp.doLogApp("channel unregistered...");
	}
	
	/**
	 * 释放指定资源
	 * 
	 * @param ctx
	 */
	private void releaseResouces(ChannelHandlerContext ctx) {
		String uid = pool.getUid(ctx.channel());
		TableWatchingCache.remove(uid);
		GamesDataWatchingCache.removeWatching(uid);
		pool.dropSession(ctx.channel());
	}
}